package com.baishui.context.annotation;

import com.baishui.beans.BeanDefinition;
import com.baishui.beans.factory.exception.BeanDefinitionStoreException;
import com.baishui.beans.factory.support.BeanDefinitionRegistry;
import com.baishui.beans.factory.support.BeanNameGenerator;
import com.baishui.core.Resource;
import com.baishui.core.io.support.PackageResourceLoader;
import com.baishui.core.type.classreading.AnnotationMetadataReadingVisitor;
import com.baishui.core.type.classreading.MetadataReader;
import com.baishui.core.type.classreading.SimpleMetadataReader;
import com.baishui.stereotype.Component;
import com.baishui.utils.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 扫描后将class文件保存为BeanDefiniton
 */
public class ClassPathBeanDefinitionScanner {

	private final BeanDefinitionRegistry registry;
	
	private PackageResourceLoader resourceLoader = new PackageResourceLoader();
	
	protected final Log logger = LogFactory.getLog(getClass());
	
	private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {		
		this.registry = registry;		
	}

	/**
	 * @param packagesToScan 包路径
	 * @return 可以不同返回
	 */
	public void/*Set<BeanDefinition>*/ doScan(String packagesToScan) {
		/**
		 * 存在多个以逗号分隔
		 */
		String[] basePackages = StringUtils.tokenizeToStringArray(packagesToScan,",");
		
//		Set<BeanDefinition> beanDefinitions = new LinkedHashSet<BeanDefinition>();
		for (String basePackage : basePackages) {

			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
//				beanDefinitions.add(candidate);
				registry.registerBeanDefinition(candidate.getID(),candidate);
				
			}
		}
//		return beanDefinitions;
	}

	/**
	 *
	 * @param basePackage 单个的包路径
	 * @return
	 */
	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		try {
			/**
			 * 获取到各个class的Resouce对象
			 */
			Resource[] resources = this.resourceLoader.getResources(basePackage);
			for (Resource resource : resources) {
				try {
					/**
					 * class的元数据对象
					 * @see AnnotationMetadataReadingVisitor 集大成者，实现了class和注解的 ClassVisitor-ASM
					 */
					MetadataReader metadataReader = new SimpleMetadataReader(resource);
					//TODO 待拓展
					if(metadataReader.getAnnotationMetadata().hasAnnotation(Component.class.getName())){
						/**
						 * 创建Bean的定义信息
						 */
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader.getAnnotationMetadata());

						String beanName = this.beanNameGenerator.generateBeanName(sbd, this.registry);
						sbd.setId(beanName);
						candidates.add(sbd);					
					}
				} catch (Throwable ex) {
					throw new BeanDefinitionStoreException(
							"Failed to read candidate component class: " + resource, ex);
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}
	
}
